#include "ISEA4DQuery.hpp"
#include<cmath>

using namespace NNU::DGGS::Kernel;

using namespace NNU::DGGS::Kernel::ISEA4D;

void ISEA4DQuery::init()
{
    for (int i = 0; i <MaxLevel; i++)
    {
        this->maxRow[i] =  (long long int)(pow(2, i));
        this->fMaxCol[i] =  (long long int)(pow(2, i));
        this->eMaxCol[i] = (long long int)(pow(2, i+1));
        this->vMaxCol[i] = (long long int)(pow(2, i));
    }
}

ISEA4DQuery::~ISEA4DQuery()
{
    delete[] this->maxRow;
    delete[] this->fMaxCol;
    delete[] this->eMaxCol;
    delete[] this->vMaxCol;
}

//获取二十面体大菱形块列表
int* ISEA4DQuery::getDiamondList(int basePartition)
{
    if (basePartition == 0)
    {
        int* diamondList = new int[5];
        diamondList[0] = 3;
        diamondList[1] = 4;
        diamondList[2] = 5;
        diamondList[3] = 1;
        diamondList[4] = 2;
        return diamondList;
    }
    else if (basePartition == 11)
    {
        int* diamondList = new int[5];
        diamondList[0] = 10;
        diamondList[1] = 9;
        diamondList[2] = 8;
        diamondList[3] = 7;
        diamondList[4] = 6;
        return diamondList;
    }
    else if (basePartition < 6)
    {
        int* diamondList = new int[4];
        int case2adjTbl[][4] = {
                {5, 2, 6, 10},  // q == 1
                {1, 3, 7, 6},   // q == 2
                {2, 4, 8, 7},   // q == 3
                {3, 5, 9, 8},   // q == 4
                {4, 1, 10, 9} }; // q == 5
        diamondList[0] = case2adjTbl[basePartition - 1][0];
        diamondList[1] = case2adjTbl[basePartition - 1][1];
        diamondList[2] = case2adjTbl[basePartition - 1][2];
        diamondList[3] = case2adjTbl[basePartition - 1][3];
        return diamondList;
    }
    else if (basePartition <= 10)
    {
        int* diamondList = new int[4];
        int case2adjTbl[][4] = {
                {1, 2, 7, 10},  // q == 6
                {2, 3, 8, 6},   // q == 7
                {3, 4, 9, 7},   // q == 8
                {4, 5, 10, 8},  // q == 9
                {5, 1, 6, 9} };  // q == 10
        diamondList[0] = case2adjTbl[basePartition - 6][0];
        diamondList[1] = case2adjTbl[basePartition - 6][1];
        diamondList[2] = case2adjTbl[basePartition - 6][2];
        diamondList[3] = case2adjTbl[basePartition - 6][3];
        return diamondList;
    }
    else
    {
        return nullptr;
    }
}

//点找面
void ISEA4DQuery::fromVertexSearchRelativeCells(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    int basePartition = code.basePartition;
    long long int row = code.row;
    long long int col = code.col;
    int* diamondList = getDiamondList(code.basePartition);

    //点找边，进而找到侧面
    int edgesNum=0;
    DGGSElementCode *edges=nullptr;
    this->fromVertexGetAssociationBoundary(code,edges,edgesNum);
    if(code.levelZ == -1)//维度
    {
        elementNum=edgesNum;
        results = new DGGSElementCode[elementNum];
    }
    else
    {
        elementNum=(edgesNum-2)*3;
        results = new DGGSElementCode[elementNum];
        for (int i = 0; i < edgesNum-2; i++)
        {
            results[i+(edgesNum-2)*2]=edges[i];
            results[i+(edgesNum-2)*2].elementType =DGGSElementType::SideFace;

            results[i+(edgesNum-2)]=results[i+(edgesNum-2)*2];
            results[i+(edgesNum-2)].levelZ= code.levelZ + 1;
        }
    }

    //北极点5个邻接面
    if(basePartition<6&&((row==0)&&(col==this->fMaxCol[code.level])))
    {
        for (int i = 0; i < 5; i++)
        {
            results[i].levelZ=code.levelZ;
            results[i].level = code.level;
            results[i].elementType =DGGSElementType::Cell;
            results[i].basePartition=diamondList[i];
            results[i].row = 0;
            results[i].col = this->fMaxCol[code.level] - 1;
        }
    }
    //南极点5个邻接面
    else if(basePartition>=6&&((row==this->fMaxCol[code.level])&&(col==0)))
    {
        for (int i = 0; i < 5; i++)
        {
            results[i].levelZ=code.levelZ;
            results[i].level = code.level;
            results[i].elementType =DGGSElementType::Cell;
            results[i].basePartition=diamondList[i];
            results[i].row = this->fMaxCol[code.level]-1;
            results[i].col = 0;
        }
    }

    //菱形4个顶点4个邻接面
        //原点
    else if((row==0)&&(col==0))
    {
        for (int i = 0; i < 3; i++)
        {
            results[i].level = code.level;
            results[i].elementType =DGGSElementType::Cell;
            results[i].levelZ=code.levelZ;
        }
        results[1].basePartition=basePartition;
        results[1].row = 0;
        results[1].col = 0;
        if(basePartition<6)
        {
            results[0].basePartition=diamondList[0];
            results[0].row = this->fMaxCol[code.level]-1;
            results[0].col = this->fMaxCol[code.level]-1;
            results[2].basePartition=diamondList[3];
            results[2].row = 0;
            results[2].col = this->fMaxCol[code.level]-1;
        }
        else
        {
            results[0].basePartition=diamondList[0];
            results[0].row = this->fMaxCol[code.level]-1;
            results[0].col = 0;
            results[2].basePartition=diamondList[3];
            results[2].row = this->fMaxCol[code.level]-1;
            results[2].col = this->fMaxCol[code.level]-1;
        }
    }
        //上点(只看下半球)
    else if((row==0)&&(col==this->fMaxCol[code.level]))
    {
        for (int i = 0; i < 3; i++)
        {
            results[i].levelZ=code.levelZ;
            results[i].level = code.level;
            results[i].elementType =DGGSElementType::Cell;
        }
        results[0].basePartition=diamondList[0];
        results[0].row = this->fMaxCol[code.level]-1;
        results[0].col = this->fMaxCol[code.level]-1;
        results[1].basePartition=diamondList[1];
        results[1].row = 0;
        results[1].col = 0;
        results[2].basePartition=basePartition;
        results[2].row = 0;
        results[2].col = this->fMaxCol[code.level]-1;
    }
        //下点（只看上半球）
    else if((row==this->fMaxCol[code.level])&&(col==0))
    {
        for (int i = 0; i < 4; i++)
        {
            results[i].levelZ=code.levelZ;
            results[i].level = code.level;
            results[i].elementType =DGGSElementType::Cell;
        }
        results[0].basePartition=basePartition;
        results[0].row = this->fMaxCol[code.level]-1;
        results[0].col = 0;
        results[1].basePartition=diamondList[2];
        results[1].row = 0;
        results[1].col = 0;
        results[2].basePartition=diamondList[3];
        results[2].row = this->fMaxCol[code.level]-1;
        results[2].col = this->fMaxCol[code.level]-1;
    }
        //半球0边，上、右、下  0邻菱形
    else if(row==0)
    {
        for (int i = 0; i < 4; i++)
        {
            results[i].levelZ=code.levelZ;
            results[i].level = code.level;
            results[i].elementType =DGGSElementType::Cell;
        }
        if(basePartition<6)
        {
            results[0].basePartition=diamondList[0];
            results[0].row=this->fMaxCol[code.level]-1-col;
            results[0].col=this->fMaxCol[code.level]-1;
            results[3].basePartition=diamondList[0];
            results[3].row=this->fMaxCol[code.level]-col;
            results[3].col=this->fMaxCol[code.level]-1;
        }
        else
        {
            results[0].basePartition=diamondList[0];
            results[0].row=this->fMaxCol[code.level]-1;
            results[0].col=col;
            results[3].basePartition=diamondList[0];
            results[3].row=this->fMaxCol[code.level]-1;
            results[3].col=col-1;
        }
        results[1].basePartition=basePartition;
        results[1].row=row;
        results[1].col=col;
        results[2].basePartition=basePartition;
        results[2].row=row;
        results[2].col=col-1;

    }
        //半球3边，左、上、右  3邻菱形
    else if(col==0)
    {
        for (int i = 0; i < 4; i++)
        {
            results[i].levelZ=code.levelZ;
            results[i].level = code.level;
            results[i].elementType =DGGSElementType::Cell;
        }
        if(basePartition<6)
        {
            results[0].basePartition=diamondList[3];
            results[0].row=row-1;
            results[0].col=this->fMaxCol[code.level]-1;
            results[3].basePartition=diamondList[3];
            results[3].row=row;
            results[3].col=this->fMaxCol[code.level]-1;
        }
        else
        {
            results[0].basePartition=diamondList[3];
            results[0].row=this->fMaxCol[code.level]-1;
            results[0].col=this->fMaxCol[code.level]-row;
            results[3].basePartition=diamondList[3];
            results[3].row=this->fMaxCol[code.level]-1;
            results[3].col=this->fMaxCol[code.level]-row-1;
        }
        results[1].basePartition=basePartition;
        results[1].row=row-1;
        results[1].col=0;
        results[2].basePartition=basePartition;
        results[2].row=row;
        results[2].col=0;


    }
        //半球1边，左、右、下  1邻菱形
    else if(col==this->fMaxCol[code.level])
    {
        for (int i = 0; i < 4; i++)
        {
            results[i].levelZ=code.levelZ;
            results[i].level = code.level;
            results[i].elementType =DGGSElementType::Cell;
        }
        if(basePartition<6)
        {
            results[1].basePartition=diamondList[1];
            results[1].row=0;
            results[1].col=this->fMaxCol[code.level]-row;
            results[2].basePartition=diamondList[1];
            results[2].row=0;
            results[2].col=this->fMaxCol[code.level]-1-row;
        }
        else
        {
            results[1].basePartition=diamondList[1];
            results[1].row=row-1;
            results[1].col=0;
            results[2].basePartition=diamondList[1];
            results[2].row=row;
            results[2].col=0;
        }
        results[0].basePartition=basePartition;
        results[0].row=row-1;
        results[0].col=col-1;
        results[3].basePartition=basePartition;
        results[3].row=row;
        results[3].col=col-1;
    }
        //半球2边，左、上、下、2邻菱形
    else if(row==this->fMaxCol[code.level])
    {
        for (int i = 0; i < 4; i++)
        {
            results[i].levelZ=code.levelZ;
            results[i].level = code.level;
            results[i].elementType =DGGSElementType::Cell;
        }
        if(basePartition<6)
        {
            results[2].basePartition=diamondList[2];
            results[2].row=0;
            results[2].col=col;
            results[3].basePartition=diamondList[2];
            results[3].row=0;
            results[3].col=col-1;
        }
        else
        {
            results[2].basePartition=diamondList[2];
            results[2].row=this->fMaxCol[code.level]-col-1;
            results[2].col=0;
            results[3].basePartition=diamondList[2];
            results[3].row=this->fMaxCol[code.level]-col;
            results[3].col=0;
        }
        results[0].basePartition=basePartition;
        results[0].row=this->fMaxCol[code.level]-1;
        results[0].col=col-1;
        results[1].basePartition=basePartition;
        results[1].row=this->fMaxCol[code.level]-1;
        results[1].col=col;
    }
    else
    {
        for (int i = 0; i < 4; i++)
        {
            results[i].levelZ=code.levelZ;
            results[i].level = code.level;
            results[i].elementType =DGGSElementType::Cell;
        }
        results[0].basePartition=basePartition;
        results[0].row=row-1;
        results[0].col=col-1;
        results[1].basePartition=basePartition;
        results[1].row=row-1;
        results[1].col=col;
        results[2].basePartition=basePartition;
        results[2].row=row;
        results[2].col=col;
        results[3].basePartition=basePartition;
        results[3].row=row;
        results[3].col=col-1;
    }
    delete []diamondList;
    if (edges != nullptr)
        delete []edges;
}

//点找边
void ISEA4DQuery::fromVertexGetAssociationBoundary(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    int basePartition = code.basePartition;
    long long int row = code.row;
    long long int col = code.col;
    int* diamondList = getDiamondList(code.basePartition);

    if(code.levelZ == -1)//维度
        elementNum=0;
    else
        elementNum=2;

    if(basePartition==0||basePartition==11)
    {
        elementNum+=5;
        results = new DGGSElementCode[elementNum];
        for (int i = 0; i < 5; i++)
        {
            results[i].level = code.level;
            results[i].elementType = DGGSElementType::Edge;
            results[i].levelZ=code.levelZ;
        }
        if(basePartition<6)
        {
            for (int i = 0; i < 5; i++)
            {
                results[i].basePartition=diamondList[i];
                results[i].row = 0;
                results[i].col = this->eMaxCol[code.level]-1;
            }
        }
        else
        {
            for (int i = 0; i < 5; i++)
            {
                results[i].basePartition=diamondList[i];
                results[i].row = this->vMaxCol[code.level]-1;
                results[i].col = 0;
            }
        }
    }
    else if(row==0&&col==0)//只有三个邻接边
    {
        elementNum+=3;
        results = new DGGSElementCode[elementNum];
        for (int i = 0; i < 3; i++)
        {
            results[i].level = code.level;
            results[i].elementType = DGGSElementType::Edge;
            results[i].levelZ=code.levelZ;
        }
        results[0].basePartition=basePartition;
        results[0].row = 0;
        results[0].col = 0;
        results[1].basePartition=basePartition;
        results[1].row = 0;
        results[1].col = 1;
        if(basePartition<6)
        {
            results[2].basePartition=diamondList[3];
            results[2].row = 0;
            results[2].col = this->eMaxCol[code.level]-1;
        }
        else
        {
            results[2].basePartition=diamondList[0];
            results[2].row = this->fMaxCol[code.level]-1;
            results[2].col = 0;
        }

    }
    else //4个邻接边
    {
        elementNum+=4;
        results = new DGGSElementCode[elementNum];
        for (int i = 0; i < 4; i++)
        {
            results[i].level = code.level;
            results[i].elementType = DGGSElementType::Edge;
            results[i].levelZ=code.levelZ;
        }
        results[0].basePartition=basePartition;
        results[0].row = row-1;
        results[0].col = 2*col;
        results[1].basePartition=basePartition;
        results[1].row = row;
        results[1].col = 2*col+1;
        results[2].basePartition=basePartition;
        results[2].row = row;
        results[2].col = 2*col;
        results[3].basePartition=basePartition;
        results[3].row = row;
        results[3].col = 2*col-1;

        if(row==0)//左上边
        {
            if(basePartition<6)
            {
                results[0].basePartition=diamondList[0];
                results[0].row = this->fMaxCol[code.level]-col;
                results[0].col = this->eMaxCol[code.level]-1;
            }
            else
            {
                results[0].basePartition=diamondList[0];
                results[0].row = this->fMaxCol[code.level]-1;
                results[0].col = col*2;
            }
        }
        else if(col==0)//左下边
        {
            if(basePartition<6)
            {
                results[3].basePartition=diamondList[3];
                results[3].row = row;
                results[3].col = this->eMaxCol[code.level]-1;
            }
            else
            {
                results[3].basePartition=diamondList[3];
                results[3].row = this->fMaxCol[code.level]-1;
                results[3].col = (this->fMaxCol[code.level]-row)*2;
            }
        }
    }

    if(code.levelZ != -1)
    {
        results[elementNum-2]=code;
        results[elementNum-2].elementType=DGGSElementType::SideEdge;
        results[elementNum-1]=results[elementNum-2];
        results[elementNum-1].levelZ+=1;
    }

    delete[] diamondList;
}

//边找点
void ISEA4DQuery::fromEdgeGetBoundary(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    elementNum=2;
    int basePartition = code.basePartition;
    long long int row = code.row;
    long long int col = code.col;
    int* diamondList = getDiamondList(code.basePartition);
    results = new DGGSElementCode[2];

    //棱边
    if(code.elementType==DGGSElementType::SideEdge)
    {
        results[0]=code;
        results[0].elementType=DGGSElementType::Vertex;
        results[1]=results[0];
        results[1].levelZ= code.levelZ - 1;
        delete[]diamondList;
        return;
    }

    //一般情况
    for (int i = 0; i < 2; i++)
    {
        results[i].level = code.level;
        results[i].elementType = DGGSElementType::Vertex;
        results[i].levelZ=code.levelZ;
    }
    if(code.col%2==0)
    {
        results[0].basePartition = basePartition;
        results[0].row = row;
        results[0].col = col/2;
        results[1].basePartition = basePartition;
        results[1].row = row+1;
        results[1].col = col/2;
    }
    else
    {
        results[0].basePartition = basePartition;
        results[0].row = row;
        results[0].col = col/2;
        results[1].basePartition = basePartition;
        results[1].row = row;
        results[1].col = col/2+1;
    }
    //右上边
    if(code.col== this->eMaxCol[code.level]-1)
    {
        if(basePartition<6)
        {
            results[1].basePartition = diamondList[1];
            results[1].row = 0;
            results[1].col = this->fMaxCol[code.level]-row;
        }
        else
        {
            results[1].basePartition =  diamondList[1];
            results[1].row = row;
            results[1].col = 0;
        }
    }
    //右下边
    if(code.row==this->fMaxCol[code.level]-1&&code.col%2==0 )
    {
        if(basePartition<6)
        {
            results[1].basePartition = diamondList[2];
            results[1].row = 0;
            results[1].col =col/2 ;
        }
        else
        {
            results[1].basePartition = diamondList[2];
            results[1].row = this->fMaxCol[code.level]-col/2;
            results[1].col = 0;
        }
    }
    //北极点
    if(code.col== this->eMaxCol[code.level]-1&&code.row==0)
    {
        if(code.basePartition<6)
        {
            results[1].basePartition = 0;
            results[1].row = 0;
            results[1].col = 0;
        }
    }
    //南极点
    if(code.row== this->fMaxCol[code.level]-1&&code.col==0)
    {
        if(code.basePartition>5)
        {
            results[1].basePartition = 11;
            results[1].row = 0;
            results[1].col = 0;
        }
    }
    delete[] diamondList;
}

//边找面
void ISEA4DQuery::fromEdgeGetAssociationBoundary(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{

    int basePartition = code.basePartition;
    long long int row = code.row;
    long long int col = code.col;
    int *diamondList = getDiamondList(code.basePartition);

    //棱边
    if(code.elementType==DGGSElementType::SideEdge)
    {
        DGGSElementCode vertex=code;
        vertex.elementType=DGGSElementType::Vertex;
        vertex.levelZ=-1;

        DGGSElementCode*edges;
        int edgeNum=0;
        this->fromVertexGetAssociationBoundary(vertex,edges,edgeNum);
        elementNum=edgeNum;
        results = new DGGSElementCode[elementNum];

        for(int i=0;i<edgeNum;i++)
        {
            results[i]=edges[i];
            results[i].elementType=DGGSElementType::SideFace;
            results[i].levelZ=code.levelZ;
        }
        delete[]edges;
        edges= nullptr;
        delete[]diamondList;
        diamondList= nullptr;
        return;
    }

    //底边
    if(code.levelZ == -1)
        elementNum=2;
    else
        elementNum=4;
    results = new DGGSElementCode[elementNum];

    for (int i = 0; i < 2; i++)
    {
        results[i].level = code.level;
        results[i].elementType = DGGSElementType::Cell;
        results[i].levelZ=code.levelZ;
    }
    if(row==0&&col==0)//原点
    {
        results[0].basePartition = basePartition;
        results[0].row = 0;
        results[0].col = 0;
        if(basePartition<6)
        {
            results[1].basePartition = diamondList[3];
            results[1].row = 0;
            results[1].col = this->fMaxCol[code.level]-1;
        }
        else
        {
            results[1].basePartition = diamondList[3];
            results[1].row = this->fMaxCol[code.level]-1;
            results[1].col = this->fMaxCol[code.level]-1;
        }

    }
    else if(row==0)//左上边
    {
        if(code.col%2==0)
        {
            results[0].basePartition = basePartition;
            results[0].row = 0;
            results[0].col = col/2-1;
            results[1].basePartition = basePartition;
            results[1].row = 0;
            results[1].col = col/2;
        }
        else
        {
            if(basePartition<6)
            {
                results[0].basePartition = diamondList[0];
                results[0].row = this->fMaxCol[code.level] - 1 - col / 2;
                results[0].col = this->fMaxCol[code.level] - 1;
            }
            else
            {
                results[0].basePartition = diamondList[0];
                results[0].row = this->fMaxCol[code.level] - 1 ;
                results[0].col = col/2;
            }
            results[1].basePartition = basePartition;
            results[1].row = row;
            results[1].col = col/2;
        }
    }
    else if(col==0)//左下边
    {
        results[0].basePartition = basePartition;
        results[0].row = row;
        results[0].col = 0;
        if(basePartition<6)
        {
            results[1].basePartition = diamondList[3];
            results[1].row = row;
            results[1].col = this->fMaxCol[code.level]-1;
        }
        else
        {
            results[1].basePartition = diamondList[3];
            results[1].row = this->fMaxCol[code.level] - 1;
            results[1].col = this->fMaxCol[code.level] - 1 - row;
        }
    }
    else
    {
        if(col%2==0)
        {
            results[0].basePartition = basePartition;
            results[0].row = row;
            results[0].col = col/2-1;
            results[1].basePartition = basePartition;
            results[1].row = row;
            results[1].col = col/2;
        }
        else
        {
            results[0].basePartition = basePartition;
            results[0].row = row-1;
            results[0].col = col/2;
            results[1].basePartition = basePartition;
            results[1].row = row;
            results[1].col = col/2;
        }
    }
    //侧面
    if(code.levelZ != -1)
    {
        results[elementNum-2]=code;
        results[elementNum-2].elementType=DGGSElementType::SideFace;
        results[elementNum-1]=results[elementNum-2];
        results[elementNum-1].levelZ= code.levelZ + 1;
    }

    delete[] diamondList;
}

//面找边
void ISEA4DQuery::fromCellGetBoundary(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    elementNum=4;
    int basePartition = code.basePartition;
    long long int row = code.row;
    long long int col = code.col;
    int *diamondList = getDiamondList(code.basePartition);
    results = new DGGSElementCode[4];

    if(code.elementType==DGGSElementType::SideFace)
    {
        results[0]=code;
        results[0].elementType=DGGSElementType::Edge;
        results[1]=results[0];
        results[1].levelZ= code.levelZ - 1;

        //找棱边
        int vertexNum=0;
        DGGSElementCode* vertex;
        this->fromEdgeGetBoundary(results[0],vertex,vertexNum);
        results[2]=vertex[0];
        results[2].elementType=DGGSElementType::SideEdge;
        results[2].levelZ=code.levelZ;
        results[3]=vertex[1];
        results[3].elementType=DGGSElementType::SideEdge;
        results[3].levelZ=code.levelZ;

        delete[]vertex;
        vertex= nullptr;
        delete[]diamondList;
        return;

    }

    for (int i = 0; i < 4; i++) {
        results[i].level = code.level;
        results[i].elementType = DGGSElementType::Edge;
        results[i].levelZ=code.levelZ;
    }

    //一般情况
    results[0].basePartition=basePartition;
    results[0].row=row;
    results[0].col=col*2+1;

    results[1].basePartition=basePartition;
    results[1].row=row;
    results[1].col=col*2+2;

    results[2].basePartition=basePartition;
    results[2].row=row+1;
    results[2].col=col*2+1;

    results[3].basePartition=basePartition;
    results[3].row=row;
    results[3].col=col*2;

    //右上边改results[1]
    if(col==this->fMaxCol[code.level]-1)
    {
        if(basePartition<6)
        {
            results[1].basePartition=diamondList[1];
            results[1].row=0;
            results[1].col=(this->fMaxCol[code.level]-1-row)*2+1;
        }
        else
        {
            results[1].basePartition=diamondList[1];
            results[1].row=row;
            results[1].col=0;
        }
    }
    //右下边改results[2]
    if(row==this->fMaxCol[code.level]-1)
    {
        if(basePartition<6)
        {
            results[2].basePartition=diamondList[2];
            results[2].row=0;
            results[2].col=col*2+1;
        }
        else
        {
            results[2].basePartition=diamondList[2];
            results[2].row=this->fMaxCol[code.level]-1-col;
            results[2].col=0;
        }
    }
    delete[] diamondList;
}

//父节点
void ISEA4DQuery::getVoxelParent(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    DGGSElementCode cell=code;
    cell.elementType=DGGSElementType::Cell;
    this->getCellParent(cell,results,elementNum);
    for(int i=0;i<elementNum;i++)
    {
        results[i].elementType=DGGSElementType::Voxel;
    }
}

void ISEA4DQuery::getCellParent(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    elementNum=1;
    results = new DGGSElementCode[1];
    results[0].level = code.level-1;
    results[0].elementType = DGGSElementType::Cell;
    results[0].basePartition = code.basePartition;
    results[0].col = code.col / 2;
    results[0].row = code.row / 2;
    results[0].levelZ=code.levelZ;
}

void ISEA4DQuery::getEdgeParent(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    elementNum=1;
    results=new DGGSElementCode[elementNum];
    results[0].basePartition = code.basePartition;
    results[0].level=code.level-1;
    results[0].levelZ=code.levelZ;

    if(code.col%4==0)
    {
        results[0].row=code.row/2;
        results[0].col=code.col/2;
    }
    else if(code.col%2==1&&code.row%2==0)
    {
        results[0].row=code.row/2;
        if(code.col%4==1)
            results[0].col=(code.col+1)/2;
        else
            results[0].col=(code.col-1)/2;
    }
    else
    {
        int edgesNum;
        DGGSElementCode *edges= nullptr;
        this->fromEdgeGetRelativeEdges(code,edges,edgesNum);
        for(int i=0;i<edgesNum;i++)
        {
            if(edges[i].col%4==0||(edges[i].col%2==1&&edges[i].row%2==0))
            {
                int parentNum;
                DGGSElementCode *parents= nullptr;
                this->getEdgeParent(edges[i],parents,parentNum);
                results[0]=parents[0];
                delete[]parents;
                parents= nullptr;
                break;
            }
        }
        delete[]edges;
        edges= nullptr;

    }
}

void ISEA4DQuery::getVertexParent(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    if((code.row%2==1&&code.col%2==1)||(code.row%2==0&&code.col%2==0))
    {
        elementNum=1;
        results=new DGGSElementCode[elementNum];
        results[0]=code;
        results[0].col/=2;
        results[0].row/=2;
        results[0].level-=1;
    }
    else
    {
        int levelD=code.levelZ;
        code.levelZ=-1;
        elementNum=0;
        results=new DGGSElementCode[2];
        int vertexexNum;
        DGGSElementCode *vertexes= nullptr;
        this->fromVertexGetRelativeVertexes(code,vertexes,vertexexNum);
        for(int i=0;i<vertexexNum;i++)
        {
            if((vertexes[i].row%2==0&&vertexes[i].col%2==0))
            {
                int parentNum;
                DGGSElementCode* parent= nullptr;
                this->getVertexParent(vertexes[i],parent,parentNum);
                results[elementNum]=parent[0];
                results[elementNum].levelZ=levelD;
                elementNum++;

                delete[]parent;
                parent= nullptr;
            }
        }

    }
}
//子节点
void ISEA4DQuery::getVoxelChildren(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    DGGSElementCode cell=code;
    cell.elementType=DGGSElementType::Cell;
    this->getCellChildren(cell,results,elementNum);
    for(int i=0;i<elementNum;i++)
    {
        results[i].elementType=DGGSElementType::Voxel;
    }
}

void ISEA4DQuery::getCellChildren(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    elementNum=4;
    results = new DGGSElementCode[4];

    int addNum[4][2]={
            {0,1},
            {1,1},
            {1,0},
            {0,0}
    };
    for (int i = 0; i < 4; i++) {
        results[i].levelZ=code.levelZ;
        results[i].level = code.level+1;
        results[i].elementType = DGGSElementType::Cell;
        results[i].basePartition = code.basePartition;
        results[i].row=code.row*2+addNum[i][0];
        results[i].col=code.col*2+addNum[i][1];
    }
}

void ISEA4DQuery::getEdgeChildren(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    int *diamondList = getDiamondList(code.basePartition);
    elementNum=4;
    results=new DGGSElementCode[elementNum];
    if(code.col%2==1)
    {
        DGGSElementCode interiorChild=code;
        interiorChild.level+=1;
        interiorChild.row*=2;
        interiorChild.col*=2;
        for(int i=0;i<elementNum;i++)
            results[i]=interiorChild;
        results[0].row-=1;
        results[1].col+=1;
        results[3].col-=1;
    }
    else
    {
        DGGSElementCode interiorChild=code;
        interiorChild.level+=1;
        interiorChild.row*=2;
        interiorChild.col*=2;
        for(int i=0;i<elementNum;i++)
            results[i]=interiorChild;
        results[1].row+=1;results[1].col+=1;
        results[2].row+=1;
        results[3].row+=1;results[3].col-=1;
    }

    if(code.row==0&&code.col%2==1)
    {
        if(code.basePartition<6)
        {
            results[0].basePartition= diamondList[0];
            results[0].row=this->maxRow[results[0].level]-results[0].col/2;
            results[0].col=this->maxRow[results[0].level]-1;
        }
        else
        {
            results[0].basePartition= diamondList[0];
            results[0].row=this->maxRow[results[0].level]-1;
        }
    }
    if(code.col==0)
    {
        if(code.basePartition<6)
        {
            results[3].basePartition= diamondList[3];
            results[3].col=this->maxRow[results[3].level]-1;

        }
        else
        {
            results[3].basePartition= diamondList[3];
            results[3].col=(this->maxRow[results[3].level]-results[3].row)*2;
            results[3].row=this->maxRow[results[3].level]-1;
        }
    }
}

void ISEA4DQuery::getVertexChildren(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    DGGSElementCode interiorChild=code;
    interiorChild.row*=2;
    interiorChild.col*=2;
    interiorChild.level+=1;
    interiorChild.levelZ=-1;

    int vertexesNum;
    DGGSElementCode*vertexes= nullptr;
    this->fromVertexGetRelativeVertexes(interiorChild,vertexes,vertexesNum);

    elementNum=vertexesNum+2;
    results=new DGGSElementCode[elementNum];
    results[0]=interiorChild;
    results[1]={DGGSElementType::Vertex,-1,interiorChild.level,interiorChild.basePartition,interiorChild.row+1,interiorChild.col+1};
    for(int i=0;i<vertexesNum;i++)
        results[i+2]=vertexes[i];
    for(int i=0;i<elementNum;i++)
        results[i].levelZ=code.levelZ;

    delete[]vertexes;
    vertexes= nullptr;

}
//兄弟节点
void ISEA4DQuery::getVoxelSiblings(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    DGGSElementCode cell=code;
    cell.elementType=DGGSElementType::Cell;
    this->getCellSiblings(cell,results,elementNum);
    for(int i=0;i<elementNum;i++)
    {
        results[i].elementType=DGGSElementType::Voxel;
    }
}

void ISEA4DQuery::getCellSiblings(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    elementNum=3;
    DGGSElementCode* parents= nullptr;
    DGGSElementCode* children= nullptr;
    int parentNum;
    this->getCellParent(code,parents,parentNum);
    int childrenNum;
    this->getCellChildren(parents[0],children,childrenNum);

    results=new DGGSElementCode[3];
    int size=0;
    for(int i=0;i<childrenNum;i++)
    {
        if(children[i].col==code.col&&children[i].row==code.row)continue;
        results[size++]=children[i];
    }

    delete []parents;
    delete []children;

}

void ISEA4DQuery::getEdgeSiblings(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    int parentNum;
    DGGSElementCode*parent= nullptr;
    this->getEdgeParent(code,parent,parentNum);

    int firEdgesNum=0;
    DGGSElementCode*firEdges= nullptr;
    this->getEdgeChildren(parent[0],firEdges,firEdgesNum);

    int secEdgesNum=0;
    DGGSElementCode*secEdges= nullptr;
    if(parentNum==2)
        this->getEdgeChildren(parent[1],secEdges,secEdgesNum);

    elementNum=0;
    results=new DGGSElementCode[firEdgesNum+secEdgesNum];
    for(int i=0;i<firEdgesNum;i++)
    {
        if(code.row==firEdges[i].row&&code.col==firEdges[i].col&&code.basePartition==firEdges[i].basePartition)
            continue;
        results[elementNum++]=firEdges[i];
    }
    for(int i=0;i<secEdgesNum;i++)
    {
        if(code.row==secEdges[i].row&&code.col==secEdges[i].col&&code.basePartition==secEdges[i].basePartition)
            continue;
        results[elementNum++]=secEdges[i];
    }

    delete[]parent;
    parent= nullptr;
    delete[]firEdges;
    firEdges= nullptr;
    if(secEdges)
    {
        delete[]secEdges;
        secEdges= nullptr;
    }
}

void ISEA4DQuery::getVertexSiblings(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    int parentNum;
    DGGSElementCode*parent= nullptr;
    this->getVertexParent(code,parent,parentNum);

    int firVertexNum=0;
    DGGSElementCode*firVertexes= nullptr;
    this->getVertexChildren(parent[0], firVertexes, firVertexNum);

    int secVertexesNum=0;
    DGGSElementCode*secVertexes= nullptr;
    if(parentNum==2)
        this->getVertexChildren(parent[1], secVertexes, secVertexesNum);

    elementNum=0;
    results=new DGGSElementCode[firVertexNum+secVertexesNum];
    for(int i=0; i < firVertexNum; i++)
    {
        if(code.row == firVertexes[i].row && code.col == firVertexes[i].col && code.basePartition == firVertexes[i].basePartition)
            continue;
        results[elementNum++]=firVertexes[i];
    }
    for(int i=0; i < secVertexesNum; i++)
    {
        if(code.row == secVertexes[i].row && code.col == secVertexes[i].col && code.basePartition == secVertexes[i].basePartition)
            continue;
        results[elementNum++]=secVertexes[i];
    }

    delete[]parent;
    parent= nullptr;
    delete[]firVertexes;
    firVertexes= nullptr;
    if(secVertexes)
    {
        delete[]secVertexes;
        secVertexes= nullptr;
    }
}
//面找面
void ISEA4DQuery::fromCellGetRelativeCells(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    //面找边
    DGGSElementCode *edges= nullptr;
    int edgesNum;
    this->fromCellGetBoundary(code,edges,edgesNum);
    if(code.levelZ == -1)
        elementNum=edgesNum;
    else
        elementNum=edgesNum*3;
    results = new DGGSElementCode[elementNum];

    //边找面
    int resultsCount=0;
    for(int i=0;i<edgesNum;i++)
    {
        DGGSElementCode *cells= nullptr;
        int cellNum;
        this->fromEdgeGetAssociationBoundary(edges[i],cells,cellNum);
        for(int j=0;j<cellNum;j++)
        {
            DGGSElementCode temp=cells[j];
            if(cells[j].basePartition==code.basePartition&&cells[j].col==code.col&&cells[j].row==code.row)
                continue;
            results[resultsCount++]=cells[j];
        }
        delete []cells;
        cells= nullptr;
    }
    delete []edges;
    edges= nullptr;
}

//面找点
void ISEA4DQuery::fromCellGetRelativeVertexes(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    elementNum=4;
    results=new DGGSElementCode[4];
    DGGSElementCode * edges= nullptr;
    int edgesNum;
    this->fromCellGetBoundary(code,edges,edgesNum);

    int resultCount=0;
    for(int i=0;i<edgesNum;i++)
    {
        DGGSElementCode *vertexes= nullptr;
        int vertexNum;
        this->fromEdgeGetBoundary(edges[i], vertexes, vertexNum);

        for(int k=0;k<2;k++)
        {
            int j=0;
            for(;j<resultCount;j++)
                if(results[j].col == vertexes[k].col && results[j].basePartition == vertexes[k].basePartition && results[j].row == vertexes[k].row)
                    break;
            if(j==resultCount)
                results[resultCount++]=vertexes[k];
        }
        delete []vertexes;
        vertexes= nullptr;
    }
    delete []edges;
    edges= nullptr;
}

//点找点
void ISEA4DQuery::fromVertexGetRelativeVertexes(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    int size=0;
    DGGSElementCode* edges= nullptr;
    int edgesNum;
    this->fromVertexGetAssociationBoundary(code,edges,edgesNum);
    elementNum=edgesNum;
    results=new DGGSElementCode[elementNum];
    for(int i=0;i<edgesNum;i++)
    {
        DGGSElementCode*vertexes= nullptr;
        int vertexsNum;
        fromEdgeGetBoundary(edges[i], vertexes, vertexsNum);
        for(int j=0;j<vertexsNum;j++)
        {
            if(code.row == vertexes[j].row && code.col == vertexes[j].col && code.basePartition == vertexes[j].basePartition)
                continue;
            else
                results[size++]=vertexes[j];
        }
        delete vertexes;
    }
    delete []edges;
    edges= nullptr;
}

//边找边
void ISEA4DQuery::fromEdgeGetRelativeEdges(DGGSElementCode code, DGGSElementCode*& results, int& elementNum)
{
    elementNum=0;
    DGGSElementCode* vertexes= nullptr;
    int vertexesNum;
    this->fromEdgeGetBoundary(code, vertexes, vertexesNum);

    DGGSElementCode* FirEdges= nullptr;
    DGGSElementCode* SecEdges= nullptr;
    int Fir_edgesNum,Sec_edgesNum;
    this->fromVertexGetAssociationBoundary(vertexes[0], FirEdges, Fir_edgesNum);
    this->fromVertexGetAssociationBoundary(vertexes[1], SecEdges, Sec_edgesNum);
    results=new DGGSElementCode[Fir_edgesNum+Sec_edgesNum-2];

    for(int j=0;j<Fir_edgesNum;j++)
    {
        if(FirEdges[j].col==code.col&&FirEdges[j].row==code.row&&FirEdges[j].basePartition==code.basePartition)
            continue;
        results[elementNum++]=FirEdges[j];
    }
    for(int j=0;j<Sec_edgesNum;j++)
    {
        if(SecEdges[j].col==code.col&&SecEdges[j].row==code.row&&SecEdges[j].basePartition==code.basePartition)
            continue;
        results[elementNum++]=SecEdges[j];
    }

    delete FirEdges;
    FirEdges=nullptr;
    delete SecEdges;
    SecEdges= nullptr;
    delete vertexes;
    vertexes= nullptr;
}

//体找面
void ISEA4DQuery::fromVoxelGetRelativeCells(DGGSElementCode code, DGGSElementCode *&results, int &elementNum)
{
    int edgesNum=0;
    DGGSElementCode*edges= nullptr;

    DGGSElementCode*cell;
    cell=new DGGSElementCode[1];
    cell[0]=code;
    cell[0].elementType=DGGSElementType::Cell;

    this->fromCellGetBoundary(cell[0],edges,edgesNum);
    elementNum=edgesNum+2;
    results=new DGGSElementCode[elementNum];

    results[0]=code;
    results[0].elementType=DGGSElementType::Cell;
    results[1]=results[0];
    results[1].levelZ= code.levelZ - 1;

    for(int i=0;i<edgesNum;i++)
    {
        results[i+2]=edges[i];
        results[i+2].elementType=DGGSElementType::SideFace;
    }
    delete []cell;
    cell= nullptr;
    delete[] edges;
    edges= nullptr;
}

//体找边
void ISEA4DQuery::fromVoxelGetRelativeEdges(DGGSElementCode code, DGGSElementCode *&results, int &elementNum)
{
    elementNum=4*3;
    results=new DGGSElementCode[elementNum];

    //上下面
    int cellNum=0;
    DGGSElementCode* cells;
    cells=new DGGSElementCode[2];
    cells[0]=code;
    cells[0].elementType=DGGSElementType::Cell;
    cells[1]=cells[0];
    cells[1].levelZ= code.levelZ - 1;
    for(int i=0;i<2;i++)
    {
        int edgesNum=0;
        DGGSElementCode*edges= nullptr;
        this->fromCellGetBoundary(cells[i],edges,edgesNum);
        for(int j=0;j<edgesNum;j++)
            results[i*edgesNum+j]=edges[j];
        delete []edges;
        edges= nullptr;
    }

    //棱边
    int vertexNum=0;
    DGGSElementCode* vertex;
    this->fromCellGetRelativeVertexes(cells[0],vertex,vertexNum);

    for(int k=0;k<vertexNum;k++)
    {
        results[vertexNum*2+k]=vertex[k];
        results[vertexNum*2+k].elementType=DGGSElementType::SideEdge;
    }
    delete []vertex;
    vertex= nullptr;
    delete []cells;
    cells= nullptr;

}

//体找点
void ISEA4DQuery::fromVoxelGetRelativeVertexes(DGGSElementCode code, DGGSElementCode *&results, int &elementNum) {
    elementNum=4*2;
    results=new DGGSElementCode[elementNum];

    //上下面
    int cellNum=0;
    DGGSElementCode* cells= nullptr;
    cells=new DGGSElementCode[2];
    cells[0]=code;
    cells[0].elementType=DGGSElementType::Cell;
    cells[1]=cells[0];
    cells[1].levelZ= code.levelZ - 1;

    //面找点
    for(int i=0;i<2;i++)
    {
        int vertexNum=0;
        DGGSElementCode* vertexs= nullptr;
        this->fromCellGetRelativeVertexes(cells[i],vertexs,vertexNum);
        for(int j=0;j<vertexNum;j++)
        {
            results[i*vertexNum+j]=vertexs[j];
        }
        delete []vertexs;
        vertexs= nullptr;
    }

    delete[]cells;
    cells= nullptr;
}

//面找体
void ISEA4DQuery::fromCellGetRelativeVoxels(DGGSElementCode code, DGGSElementCode *&results, int &elementNum)
{
    elementNum=2;
    results=new DGGSElementCode[2];
    if(code.elementType==DGGSElementType::Cell)
    {
        results[0]=code;
        results[0].elementType=DGGSElementType::Voxel;
        results[1]=results[0];
        results[1].levelZ= code.levelZ + 1;
    }
    else if(code.elementType==DGGSElementType::SideFace)
    {
        DGGSElementCode*edges;
        edges=new DGGSElementCode[1];
        edges[0]=code;
        edges[0].elementType=DGGSElementType::Edge;

        int levelD=edges[0].levelZ;
        edges[0].levelZ=-1;
        int cellNum=0;
        DGGSElementCode *cells= nullptr;
        this->fromEdgeGetAssociationBoundary(edges[0],cells,cellNum);

        for(int i=0;i<cellNum-2;i++)
        {
            results[i]=cells[i];
            results[i].elementType=DGGSElementType::Voxel;
            results[i].levelZ=levelD;
        }
        delete [] edges;
        edges= nullptr;
        delete[]cells;
        cells= nullptr;
    }

}

//边找体
void ISEA4DQuery::fromEdgeGetRelativeVoxels(DGGSElementCode code, DGGSElementCode *&results, int &elementNum)
{
    if(code.elementType==DGGSElementType::SideEdge)
    {
        DGGSElementCode *vertex;
        vertex=new DGGSElementCode[1];
        vertex[0]=code;
        vertex[0].elementType=DGGSElementType::Vertex;

        int levelD=vertex[0].levelZ;
        vertex[0].levelZ=-1;
        DGGSElementCode * cells;
        int cellNum=0;
        this->fromVertexSearchRelativeCells(vertex[0],cells,cellNum);

        elementNum=cellNum;
        results=new DGGSElementCode[elementNum];

        for(int i=0;i<elementNum;i++)
        {
            results[i]=cells[i];
            results[i].elementType=DGGSElementType::Voxel;
            results[i].levelZ=levelD;
        }
        delete[]cells;
        cells= nullptr;
        delete[]vertex;
        vertex= nullptr;
    }
    else if(code.elementType==DGGSElementType::Edge)
    {
        elementNum=4;
        results=new DGGSElementCode[elementNum];
        DGGSElementCode * cells;
        int levelD=code.levelZ;
        code.levelZ=-1;
        int cellNum=0;
        this->fromEdgeGetAssociationBoundary(code,cells,cellNum);
        for(int i=0;i<cellNum;i++)
        {
            results[i]=cells[i];
            results[i].elementType=DGGSElementType::Voxel;
            results[i].levelZ=levelD;
            results[i+cellNum]=results[i];
            results[i+cellNum].levelZ= code.levelZ + 1;
        }
        delete[]cells;
        cells= nullptr;
    }
}

//点找体
void ISEA4DQuery::fromVertexGetRelativeVoxels(DGGSElementCode code, DGGSElementCode *&results, int &elementNum)
{
    DGGSElementCode * cells;
    int cellNum=0;
    int levelD=code.levelZ;
    code.levelZ=-1;
    this->fromVertexSearchRelativeCells(code,cells,cellNum);
    elementNum=cellNum*2;
    results=new DGGSElementCode[elementNum];

    for(int i=0;i<cellNum;i++)
    {
        results[i]=cells[i];
        results[i].elementType=DGGSElementType::Voxel;
        results[i].levelZ=levelD;

        results[i+cellNum]=results[i];
        results[i+cellNum].levelZ= code.levelZ + 1;
    }
    delete[]cells;
    cells= nullptr;
}

//体找体
void ISEA4DQuery::fromBodyGetRelativeVoxels(DGGSElementCode code, DGGSElementCode *&results, int &elementNum)
{
    DGGSElementCode cell=code;
    cell.elementType=DGGSElementType::Cell;
    cell.levelZ=-1;

    DGGSElementCode *cells;
    int cellNum;
    this->fromCellGetRelativeCells(cell,cells,cellNum);
    elementNum=cellNum+2;
    results=new DGGSElementCode[elementNum];

    for(int i=0;i<cellNum;i++)
    {
        results[i]=cells[i];
        results[i].elementType=DGGSElementType::Voxel;
        results[i].levelZ=code.levelZ;
    }

    results[elementNum-2]=code;
    results[elementNum-2].elementType=DGGSElementType::Voxel;
    results[elementNum-2].levelZ= code.levelZ - 1;

    results[elementNum-1]=code;
    results[elementNum-1].elementType=DGGSElementType::Voxel;
    results[elementNum-1].levelZ= code.levelZ + 1;

    delete[]cells;
    cells= nullptr;
}


